﻿using Microsoft.Office.InfoPath;
using mshtml;
using System;
using System.IO;
using System.Reflection;
using System.Xml.XPath;

namespace InfoPathHelpers.TaskPane
{
    public class CustomTaskPane
    {
        FormContext _FormContext;
        private HtmlTaskPane _TaskPane;
        private IHTMLWindow2 _Window;
        private bool _UseFormatting;
        private bool _ShowNavigation;
        private bool _AutoGenerateNavigation;
        private bool _ShowHelp;
        private bool _ShowValidationErrors;
        private bool _UseHelpTitlesForErrors;
        private int _NavigationMaxWidth;

        public CustomTaskPane(FormContext formContext) : this(formContext, true) { }

        public CustomTaskPane(FormContext formContext, bool useFormatting) : this(formContext, useFormatting, false) { }

        public CustomTaskPane(FormContext formContext, bool useFormatting, bool startHidden)
        {
            _FormContext = formContext;
            _TaskPane = formContext.CustomTaskPane;
            if (startHidden)
            {
                Hide();
            }
                        
            IHTMLDocument2 Doc = (IHTMLDocument2)_TaskPane.HtmlDocument;
            _Window = Doc.parentWindow;
            _UseFormatting = useFormatting;
            _ShowNavigation = true;
            _ShowHelp = true;
            _ShowValidationErrors = true;
            GenerateNavigationButtons(_UseFormatting);
            ToggleVisibility("Body", true);
        }

        private Help GetHelp(ViewInfo currentView, XPathNavigator context)
        {
            Help Help = new Help();
            string ViewName = currentView.Name;
            if (_UseFormatting)
            {
                ViewName = ViewName.Substring(2);
            }
            string XPath = string.Format("/Root/View[@name='{0}']/Help[@context='{1}']",
                ViewName, context.LocalName);
            XPathNavigator HelpNode = _FormContext.DataSources["Help"].CreateNavigator().SelectSingleNode(XPath);
            if (HelpNode == null)
            {
                Help.Title = "No help available";
                Help.Message = "There is currently no help available for this item.";
            }
            else
            {
                Help.Title = HelpNode.SelectSingleNode("./Title").Value;
                Help.Message = HelpNode.SelectSingleNode("./Message").Value;
            }
            return Help;
        }

        private Help GetHelp(ClickedEventArgs clickedEventArgs)
        {
            Help Help = new Help();
            string XPath = string.Format("/Root/Buttons/ButtonHelp[@controlId='{0}']", clickedEventArgs.ControlId);
            XPathNavigator HelpNode = _FormContext.DataSources["Help"].CreateNavigator().SelectSingleNode(XPath);
            if (HelpNode == null)
            {
                Help.Title = "No help available";
                Help.Message = "There is currently no help available for this item.";
            }
            else
            {
                Help.Title = HelpNode.SelectSingleNode("./Title").Value;
                Help.Message = HelpNode.SelectSingleNode("./Message").Value;
            }
            return Help;
        }

        public void RefreshErrors(FormErrorCollection errors)
        {
            _Window.execScript("ClearErrors()", null);
            foreach (FormError Error in errors)
            {
                var Title = Error.Site.LocalName;
                var Message = Error.Message;
                if (_UseHelpTitlesForErrors)
                {
                    string XPath = string.Format("/Root/View/Help[@context='{0}']/Title", Title);
                    XPathNavigator TitleNode = _FormContext.DataSources["Help"].CreateNavigator().SelectSingleNode(XPath);
                    if (TitleNode != null)
                    {
                        Title = TitleNode.Value;
                    }
                }
                _Window.execScript(string.Format("AddError('{0}:', '{1}')", Title, Message), null);
            }
        }

        public void SetHelp(ViewInfo currentView, XPathNavigator context)
        {
            Help Help = GetHelp(currentView, context);
            _Window.execScript(string.Format("SetHelp('{0}', '{1}')", Help.Title, Help.Message), null);
        }

        public void SetHelp(ClickedEventArgs clickedEventArgs)
        {
            Help Help = GetHelp(clickedEventArgs);
            _Window.execScript(string.Format("SetHelp('{0}', '{1}')", Help.Title, Help.Message), null);
        }

        private void GenerateNavigationButtons(bool useFormatting)
        {
            _Window.execScript(string.Format("GenerateButtons({0})", Convert.ToInt32(useFormatting).ToString()), "JScript");
        }

        public void Show()
        {
            _TaskPane.Visible = true;
        }

        public void Hide()
        {
            _TaskPane.Visible = false;
        }

        public bool ShowNavigation
        {
            get { return _ShowNavigation; }
            set
            {
                _ShowNavigation = value;
                ToggleVisibility("Navigation", value);
                ToggleVisibility("Rule1", value);
            }
        }

        public bool AutoGenerateNavigation
        {
            get { return _AutoGenerateNavigation; }
            set { _AutoGenerateNavigation = value; }
        }

        public bool ShowHelp
        {
            get { return _ShowHelp; }
            set
            {
                _ShowHelp = value;
                ToggleVisibility("Help", value);
                ToggleVisibility("Rule1", value);
            }
        }

        public bool ShowValidationErrors
        {
            get { return _ShowValidationErrors; }
            set 
            { 
                _ShowValidationErrors = value;
                ToggleVisibility("ValidationErrors", value);
                ToggleVisibility("Rule2", value);
            }
        }

        public bool UseHelpTitlesForValidationErrors
        {
            get { return _UseHelpTitlesForErrors; }
            set { _UseHelpTitlesForErrors = value; }
        }

        public int NavigationMaxWidth
        {
            get { return _NavigationMaxWidth; }
            set
            {
                _NavigationMaxWidth = value;
                SetMaxWidth("Navigation", value);
            }
        }

        public static void GetDefaultTaskPaneFile(Stream outputStream)
        {
            Resources.ResourceHandler.CopyResourceFile("InfoPathHelpers.Resources.CustomTaskPane.html", outputStream);
        }

        public static void GetDefaultHelpFile(Stream outputStream)
        {
            Resources.ResourceHandler.CopyResourceFile("InfoPathHelpers.Resources.Help.xml", outputStream);
        }

        public static void SaveDefaultTaskPaneFile(string folderPath)
        {
            Resources.ResourceHandler.SaveResourceFile(folderPath, "InfoPathHelpers.Resources.CustomTaskPane.html");
        }

        public static void SaveDefaultHelpFile(string folderPath)
        {
            Resources.ResourceHandler.SaveResourceFile(folderPath, "InfoPathHelpers.Resources.Help.xml");
        }

        private void SetMaxWidth(string elementName, int maxWidth)
        {
            _Window.execScript(string.Format("SetMaxWidth('{0}', {1})", elementName, maxWidth), "JScript");
        }

        private void ToggleVisibility(string elementName, bool isVisible)
        {
            _Window.execScript(string.Format("ToggleVisibility('{0}', {1})", elementName, Convert.ToInt32(isVisible).ToString()), "JScript");
        }

        public bool IsVisible
        {
            get { return _TaskPane.Visible; }
        }

        private class Help
        {
            private string _Context;
            private string _Title;
            private string _Message;

            public string Context
            {
                get { return _Context; }
                set { _Context = value; }
            }

            public string Title
            {
                get { return _Title; }
                set { _Title = value; }
            }

            public string Message
            {
                get { return _Message; }
                set { _Message = value; }
            }
        }
    }


}
